import 'package:dio/dio.dart';
import 'package:flutter_oss_aliyun/flutter_oss_aliyun.dart';
import 'package:get/get.dart';
import 'package:sainbainu/common/apis/common_api.dart';
import 'package:sainbainu/common/http/exception.dart';
import 'package:sainbainu/common/http/http.dart';
import 'package:sainbainu/common/http/request.dart';
import 'package:sainbainu/common/models/response/oss_auth_response.dart';
import 'package:sainbainu/common/models/response/upload_response.dart';
import 'package:sainbainu/common/repositories/common_repository.dart';
import 'package:sainbainu/common/utils/util.dart';
import 'package:sainbainu/common/values/settings.dart';

typedef ProgressCallback = void Function(int count, int total);

enum UploadMediaType {
  image,
  video,
  audio,
}

class AliOssService extends GetxService {
  static AliOssService get to => Get.find();

  late CommonRepository _commonRepository;

  late Client _client;

  Dio? _dio;

  @override
  void onInit() {
    super.onInit();
    _init();
    _commonRepository = CommonRepository(CommonApi());
  }

  /// 初始化 SDK
  _init() {
    _client = Client.init(
      ossEndpoint: AppSettings.ossEndpoint,
      bucketName: AppSettings.ossBucketName,
      authGetter: _authGetter,
    );
  }

  /// 获取 SDK 访问令牌
  Future<Auth> _authGetter() async {
    OssAuthResponse res = await _commonRepository.getAuthSts();
    return Auth(
      accessKey: res.accessKeyId ?? '',
      accessSecret: res.accessKeySecret ?? '',
      expire: res.expiration ?? '',
      secureToken: res.securityToken ?? '',
    );
  }

  /// 上传本地文件
  /// [filepath] 文件本地路径
  Future<UploadResponse> upFile(
    String filepath, {
    required UploadMediaType mediaType,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      final String fileName = Util.getFileName(filepath);
      final String keyName = Util.generateUniqueFileName(fileName);
      var res = await _client.putObjectFile(
        filepath,
        fileKey: keyName,
        option: PutRequestOption(
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress,
        ),
      );
      String path = res.requestOptions.path;
      if (mediaType == UploadMediaType.image) {
        path = await _getImageFormatPath(path);
      }
      return UploadResponse.fromJson({
        'fileName': fileName,
        'keyName': keyName,
        'url': path,
      });
    } on DioException catch (e) {
      CustomHttpException httpException = CustomHttpException.create(e);
      throw httpException;
    } catch (e) {
      throw CustomHttpException(message: e.toString());
    }
  }

  /// 图片路径携带宽高参数
  Future<String> _getImageFormatPath(String path) async {
    _dio ??= Dio();
    try {
      var res = await _dio!.get('$path?x-oss-process=image/info');
      var imgW = res.data['ImageWidth']['value'];
      var imgH = res.data['ImageHeight']['value'];
      return '$path?w=$imgW&h=$imgH';
    } catch (e) {
      return path;
    }
  }

  /// 删除 OSS 文件
  /// [keyName] 文件唯一索引
  Future<void> deleteFile(String keyName) async {
    try {
      await _client.deleteObject(keyName);
    } on DioException catch (e) {
      CustomHttpException httpException = CustomHttpException.create(e);
      throw httpException;
    } catch (e) {
      throw CustomHttpException(message: e.toString());
    }
  }

  /// 批量删除 OSS 文件
  /// [keyNames] 文件唯一索引数组
  Future<void> deleteFiles(List<String> keyNames) async {
    try {
      await _client.deleteObjects(keyNames);
    } on DioException catch (e) {
      CustomHttpException httpException = CustomHttpException.create(e);
      throw httpException;
    } catch (e) {
      throw CustomHttpException(message: e.toString());
    }
  }
}
